package com.labelimage.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.labelimage.bean.entity.*;
import com.labelimage.bean.param.DatasetParam;
import com.labelimage.bean.param.TemplateParam;
import com.labelimage.bean.vo.TaskVo;
import com.labelimage.common.constant.Constant;
import com.labelimage.common.response.WS;
import com.labelimage.controller.TaskSocketServer;
import com.labelimage.service.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;

@Service
public class AsyncTaskService {
    @Resource
    private TaskService taskService;
    @Resource
    private ImageService imageService;
    @Resource
    private DatasetService datasetService;
    @Resource
    private TaskSocketServer taskSocketServer;
    @Resource
    private LabelService labelService;
    @Resource
    private TemplateService templateService;
    @Resource
    private LabelImageService labelImageService;



    @Async
    public void createDataset(DatasetParam datasetParam) throws IOException {
        String url = datasetParam.getPath();
        if (!StrUtil.endWith(url, "/")) {
            url = url + "/";
        }
        TaskEntity taskEntity = TaskEntity.builder()
                .info("数据集--"+datasetParam.getName())
                .status(Constant.TaskStatus.ING.getValue())
                .type(Constant.TaskType.CREATE_DATASET.getValue())
                .build();
        taskService.save(taskEntity);
        sendCount();
        createDatasetProcess(datasetParam,url);
        taskEnd(taskEntity,Constant.WSAction.CREATE_DATASET);
    }

    @Transactional(rollbackFor = Exception.class)
    protected void createDatasetProcess(DatasetParam datasetParam,String url){
        DatasetEntity datasetEntity = DatasetEntity.builder()
                .datasetName(datasetParam.getName())
                .datasetDesc(datasetParam.getDescribe())
                .path(url)
                .build();
        datasetService.save(datasetEntity);
        crawl(url,datasetEntity.getId());
    }

    @Async
    public void deleteDataset(Long datasetId) throws IOException{
        TaskEntity taskEntity = TaskEntity.builder()
                .info("数据集--"+datasetService.getById(datasetId).getDatasetName())
                .status(Constant.TaskStatus.ING.getValue())
                .type(Constant.TaskType.DELETE_DATASET.getValue())
                .build();
        taskService.save(taskEntity);
        sendCount();

        deleteDatasetProcess(datasetId);
        taskEnd(taskEntity,Constant.WSAction.DELETE_DATASET);
    }

    @Transactional(rollbackFor = Exception.class)
    protected void deleteDatasetProcess(Long datasetId) {
        datasetService.removeById(datasetId);
        LambdaQueryWrapper<ImageEntity> imageEntityLambdaQueryWrapper = Wrappers.lambdaQuery();
        imageService.remove(imageEntityLambdaQueryWrapper.eq(ImageEntity::getDatasetId, datasetId));
        List<TemplateEntity> templateEntityList = templateService.lambdaQuery().eq(TemplateEntity::getDatasetId, datasetId).list();
        for (TemplateEntity template : templateEntityList)
        {
            templateService.removeById(template.getId());
            LambdaQueryWrapper<LabelEntity> labelEntityLambdaQueryWrapper = Wrappers.lambdaQuery();
            labelService.remove(labelEntityLambdaQueryWrapper
                    .eq(LabelEntity::getTemplateId, template.getId()));
            LambdaQueryWrapper<LabelImageEntity> labelImageEntityLambdaQueryWrapper = Wrappers.lambdaQuery();
            labelImageService.remove(labelImageEntityLambdaQueryWrapper
                    .eq(LabelImageEntity::getTemplateId, template.getId()));
        }
    }

    @Async
    public void createTemplate(TemplateParam templateParam) throws IOException{
        TaskEntity taskEntity = TaskEntity.builder()
                .info("模板--"+templateParam.getTemplateName())
                .status(Constant.TaskStatus.ING.getValue())
                .type(Constant.TaskType.CREATE_TEMPLATE.getValue())
                .build();
        taskService.save(taskEntity);
        sendCount();
        templateService.create(templateParam);
        taskEnd(taskEntity,Constant.WSAction.CREATE_TEMPLATE);

    }

    @Async
    public void deleteTemplate(Long templateId) throws IOException {
        TemplateEntity templateEntity = templateService.getById(templateId);
        TaskEntity taskEntity = TaskEntity.builder()
                .info("模板--"+templateEntity.getTemplateName())
                .status(Constant.TaskStatus.ING.getValue())
                .type(Constant.TaskType.DELETE_TEMPLATE.getValue())
                .build();
        taskService.save(taskEntity);
        sendCount();
        templateService.delete(templateId);
        taskEnd(taskEntity,Constant.WSAction.DELETE_TEMPLATE);
    }

    protected void taskEnd(TaskEntity taskEntity,Constant.WSAction wsAction) throws IOException
    {
        taskEntity.setStatus(Constant.TaskStatus.END.getValue());
        taskService.updateById(taskEntity);
        TaskVo taskVo = TaskVo.builder().build();
        BeanUtil.copyProperties(taskEntity,taskVo);
        sendCount();
        taskSocketServer.sendMessage2All(WS.OK(wsAction.getValue(), taskVo));
    }

    @Transactional(rollbackFor = Exception.class)
    protected void crawl(String url, Long id) {
        String html = HttpUtil.get(url);
        List<String> urlList = ReUtil.findAllGroup1("<a href=\".*?\">(.*?)</a>", ReUtil.getGroup1("<pre>(.*?)</pre>", html));
        urlList.remove(0);
        for (String u : urlList) {
            if (StrUtil.endWith(u, "/")) {
                crawl(url + u, id);
            } else {
                imageService.save(ImageEntity.builder()
                        .datasetId(id)
                        .path(url + u)
                        .imageName(u)
                        .build());
            }
        }
    }

    protected void sendCount() throws IOException{
        taskSocketServer.sendMessage2All(WS.OK(Constant.WSAction.TASK_COUNT.getValue(), taskService.lambdaQuery()
                .eq(TaskEntity::getStatus, Constant.TaskStatus.ING.getValue())
                .count()));
    }


}
